package pow

import (
	"bytes"
	"math/big"
	"publicChainSystem/tools"
	"publicChainSystem/transaction"
	"strconv"
)

/**
 *@author:zhengyilong
 *@email:1797344574@qq.com
 *@phone:13479394730
 *@DateTime:2022/2/28 9:39
 **/

const BITS = 5	//难度系数，前面有多少个0

/*
区块的hash值 < 系统给定的hash值
 */

type ProofOfWork struct {
	//如果直接用结构体，会出现包的循环引用错误
	//Block *block.Block
	//TimeStamp int64
	//PrevHash []byte
	//Data []byte
	Block BlockInterface
	Target *big.Int//系统给定的值6
	//hash值转成二进制，256位，不能用int256
}

type BlockInterface interface {
	GetTimeStamp() int64
	GetPrevHash() []byte
	//GetData() []byte
	GetTxs() []transaction.Transaction	
}

//实例化一个pow结构体，并且返回
func NewPow(block BlockInterface) *ProofOfWork{
	target := big.NewInt(1)//初始化一个大整数类型的1
	//哈希值 256 - 1 - bits	255 - bits
	target = target.Lsh(target, 255-BITS)

	pow := ProofOfWork{
		//TimeStamp: timeStamp,
		//PrevHash: prevHash,
		//Data: data,
		Block: block,
		Target: target,
	}

	return &pow
}

//用来寻找随机数的
func (pow *ProofOfWork) Run() ([]byte,int64){
	var nonce int64	//随机数
	nonce = 0
	block := pow.Block
	//block.Nonce = nonce

	timeBytes := []byte(strconv.FormatInt(block.GetTimeStamp(), 10))

	//转型	[]byte转成大整数
	num := big.NewInt(0)

	for{
		nonceBytes := []byte(strconv.FormatInt(nonce, 10))
		//将每一个交易信息序列化成字节切片后追加到一个大的字节切片中
		txsBytes := []byte{}
		for _, value := range block.GetTxs() {
			txBytes, _ := value.Serialize()
			txsBytes = append(txsBytes,txBytes...)
		}
		hashBytes := bytes.Join([][]byte{txsBytes, block.GetPrevHash(), timeBytes, nonceBytes}, []byte{})
		hash := tools.GetHash(hashBytes)	//当前区块的hash

		num = num.SetBytes(hash)//用来转换成大整数的

		if (num.Cmp(pow.Target) == -1) {
			return hash,nonce
		}
		//fmt.Printf("正在寻找nonce,当前的nonce为：%d\n",nonce)
		nonce++
	}
}